#include<iostream>
#include<memory>//智能指针的头文件
#include<sys/poll.h>
#include<unistd.h>
#include"Socket.hpp"
#include"Log.hpp"

using namespace SocketModule;
using namespace LogModule;
class PollSever
{
    const static int size = 4096;
    const static int defaultfd = -1;
public:
    PollSever(uint16_t port):_listensock(std::make_unique<TcpSocket>()), _isruning(false)
    {
        _listensock->BuildTcpServerSocketMethod(port);//一键构建套接字


        //初始化连续空间的文件描述符
        for(int i = 0; i < size; i++)
        {
            _fds[i].fd = defaultfd;
            _fds[i].events = 0;
            _fds[i].revents = 0;
        }
        //0号位置默认设置为监听的描述符,也就是说其余位置都是连接描述符
        _fds[0].fd = _listensock->Fd();
        _fds[0].events = POLLIN;
        
    }
    void Start()
    {
        _isruning = true;
        while(_isruning)
        {
            PrintFd();//打印看一下本轮监听的描述符有几个
            int time = -1;//poll的第三个参数
            int n = poll(_fds, size, time);//这里将rfds的数据真正的拷贝到了内核

            switch(n)
            {
                case -1:
                    LOG(LogLevel::DEBUG) << "poll error";
                    break;
                case 0:
                    LOG(LogLevel::DEBUG) << "poll timeout";
                    break;
                default:
                    LOG(LogLevel::DEBUG) << "有事件就绪了";
                    Dispatcher();
                    break;
            }
        }
        _isruning = false;
    }
    //事件派发器
    void Dispatcher()
    {
        //到了这里我们还要区分一下,是accept还是read读就绪这一块
        for(int i = 0; i <= size; i++)
        {
            if(_fds[i].fd == defaultfd)
            {
                //改位置没有文件描述符
                continue;
            }
            //判断该文件描述符在监听到的集合里面
            if(_fds[i].revents & POLLIN)
            {
                //判断是不是有新链接到来了 ,若不是新链接就是读取
                if(_fds[i].fd == _listensock->Fd())
                {
                    //有新链接到来
                    LOG(LogLevel::DEBUG) << "进入连接模块";
                    Accepter();
                }
                else
                {
                    //有新的连接数据到来
                    LOG(LogLevel::DEBUG) << "进入读模块";
                    Recver(i);
                }
            }
        }
    }
    //链接管理器
    void Accepter()
    {
        //这里还是不能直接进行fd因为我们仍然不能确立连接中是否有数据让我们读取,如果没有数据,仍然会进入到阻塞状态
        //到这里我们应该增添一个辅助数组了
        Inet_Addr client;
        int sockfd = _listensock->Accept(&client);
        if(sockfd >= 0)
        {
            LOG(LogLevel::DEBUG) << "get a new link, sockfd" << sockfd << "client" << client.StringAddr();

            //将创建好的连接存入到辅助数组中
            int pos = 0;
            for(;pos < size; pos++)
            {
                if(_fds[pos].fd == defaultfd)
                {
                    break;
                }
            }
            if(pos == size)
            {
                //空间已满释放文件描述符
                LOG(LogLevel::DEBUG) << "_fds is full";
                close(sockfd);
            }
            else
            {
                //找到空间
                _fds[pos].fd = sockfd;
                _fds[pos].events = POLLIN;
            }
        }
    }

    //I/O处理器
    void Recver(int pos)
    {
        //可以开始读取数据了(一定能读到)
        char buffer[1024] = {0};
        ssize_t n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            //读取成功
            std::cout << "client say@: " << buffer;
        }
        else if(n == 0)
        {
            //客户端退出
            LOG(LogLevel::DEBUG) << "client quit";
            close(_fds[pos].fd);
            _fds[pos].fd = defaultfd;
            _fds[pos].events = 0;
            _fds[pos].revents = 0;
            
        }
        else
        {
            //读取失败
            LOG(LogLevel::DEBUG) << "read error";
            close(_fds[pos].fd);
            _fds[pos].fd = defaultfd;
            _fds[pos].events = 0;
            _fds[pos].revents = 0;
        }
    }
    void PrintFd()
    {
        //打印监视的文件描述符
        std::cout << "_fds[]: ";
        for(int i = 0; i < size; i++)
        {
            if(_fds[i].fd == defaultfd)
            {
                continue;
            }
            std::cout << _fds[i].fd << " ";
        }
        std::cout << std::endl;
    }
    //暂停服务器
    void Stop()
    {
        _isruning = false;
    }
    ~PollSever()
    {
        ;
    }
private:
    std::unique_ptr<Socket> _listensock;//TCP基类监听端口的文件描述符
    bool _isruning;//服务的运行状态

    struct pollfd _fds[size];//设置能监事描述符的大小
};